package utils

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
)

//一次性申请一块大内存空间,之后不在扩容,减少内存分配次数
type CherryBuffer struct {
	buf []byte
	off int
}

func NewCherryBuffer(size int) *CherryBuffer {
	return &CherryBuffer{buf: make([]byte, size), off: 0}
}

//剩余可写入空间
func (c *CherryBuffer) Spare() int {
	return cap(c.buf) - c.off
}

//尝试腾出空间
func (c *CherryBuffer) trySpareRoom(size int) {
	fmt.Println("CherryBuffer try to spare room")
	if size < 0 {
		panic("CherryBuffer.trySpareRoom:negative count")
	}
	if cap(c.buf) > size {
		fmt.Println("CherryBuffer reset off")
		//将偏移量重置回来
		c.off = 0
	} else {
		fmt.Println("CherryBuffer try to make more room")
		//尝试开辟更多空间
		c.makeMoreRoom(size)
	}
}

//开辟新的空间
func (c *CherryBuffer) makeMoreRoom(n int) {
	c.buf = makeSlice((cap(c.buf) + n) * 2)
}

func (c *CherryBuffer) checkRoom(n int) bool {
	return n+c.off <= cap(c.buf)
}

func (c *CherryBuffer) ApplyBufferSize(n int) []byte {
	if !c.checkRoom(n) {
		c.trySpareRoom(n)
	}
	rebuffs := c.buf[c.off : c.off+n]
	c.off += n
	return rebuffs
}

var ErrTooLarge = errors.New("CherryBuffer: too large")

func makeSlice(n int) []byte {
	// If the make fails, give a known error.
	defer func() {
		if recover() != nil {
			panic(ErrTooLarge)
		}
	}()
	return make([]byte, n)
}

//实现了read和write接口
//func (c *CherryBuffer)Write(p []byte) (n int, err error){
//	needRoom := len(p)
//	if c.Spare() < needRoom {
//		c.trySpareRoom(needRoom)
//	}
//	n = copy(c.buf[c.off:],p)
//	c.off += n
//	return needRoom,nil
//}
//
//func (c *CherryBuffer)Read(p []byte) (n int, err error){
//	if c.UnreadSize() < len(p) {
//		return 0 ,io.EOF
//	}
//
//	return 0,nil
//}

type CBuffer struct {
	*bytes.Buffer
}

func NewCBuffer(buf []byte) *CBuffer {
	c := &CBuffer{}
	c.Buffer = bytes.NewBuffer(buf)
	c.Buffer.Reset()
	return c
}

func (c *CBuffer) PeekMsgLen() (uint32, error) {
	unreadBytes := c.Buffer.Bytes()
	headerReader := bytes.NewReader(unreadBytes[0:4])
	var result uint32
	err := binary.Read(headerReader, binary.LittleEndian, &result)
	return result, err
}

func (c *CBuffer) ReadableBytes() int {
	return c.Len()
}
